﻿/*
 * 由SharpDevelop创建。
 * 用户： My
 * 日期: 04/10/2017
 * 时间: 14:44
 * 
 * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO.Ports;
using System.Threading;

namespace MCUWriteRead
{
	/// <summary>
	/// Description of COMPort.
	/// </summary>
	public class COMPort: comInterface
    {
		private List <string> com_port_list = new List<string>();
		private List <string> baudrate_list = new List<string>();
		private List <string> parity_list = new List<string>();
		private List <string> data_bit_list = new List<string>();
		private List <string> stop_bit_list = new List<string>();
		
		private Dictionary<string,Parity> parity_dic = new Dictionary<string,Parity>();
		private Dictionary<string,StopBits> stop_bit_dic = new Dictionary<string,StopBits>();
		private SerialPort sp = new SerialPort();
		private volatile bool sp_open_flag = false;
		private static Mutex read_buf_mutex = new Mutex();
		List<byte> read_buf = new List<byte>();
		
		public COMPort()
		{
			COMPortSet();
			HardParameterSet();
		}
		private void COMPortSet()
		{
			bool com_exist = false;
            for (int i = 0; i < 40; i++)
            {
                try
                {
                    SerialPort sp = new SerialPort("COM" + (i + 1).ToString());
                    sp.Open();
                    sp.Close();
                    com_port_list.Add(("COM" + (i + 1)).ToString());
                    com_exist = true;
                }
                catch (Exception)
                {
                    continue;
                }
            }
            if (false == com_exist)
            {
                Console.WriteLine("没有找到可用串口！");
			}
		}
		private void HardParameterSet()
		{
			baudrate_list.Add("4800");
			baudrate_list.Add("9600");
			baudrate_list.Add("14400");
			baudrate_list.Add("19200");
			baudrate_list.Add("38400");
			baudrate_list.Add("43000");
			baudrate_list.Add("56000");
			baudrate_list.Add("57600");
			baudrate_list.Add("115200");
			baudrate_list.Add("128000");
			baudrate_list.Add("256000");
			baudrate_list.Add("500000");
			
			parity_list.Add("None(无)");
			parity_list.Add("Odd(奇)");
			parity_list.Add("Even(偶)");
			parity_list.Add("Mark(=1)");
			parity_list.Add("Space(=0)");
			parity_dic.Add("None(无)",Parity.None);
			parity_dic.Add("Odd(奇)",Parity.Odd);
			parity_dic.Add("Even(偶)",Parity.Even);
			parity_dic.Add("Mark(=1)",Parity.Mark);
			parity_dic.Add("Space(=0)",Parity.Space);

			data_bit_list.Add("7");
			data_bit_list.Add("8");

			stop_bit_list.Add("1");
			stop_bit_list.Add("2");
			stop_bit_dic.Add("1",StopBits.One);
			stop_bit_dic.Add("2",StopBits.Two);
		}

		public List<string> GetBaudList()
		{
			return baudrate_list;
		}
		public string GetDefaultBaud()
		{
			return "9600";
		}
		
		public List<string> GetCOMPortList()
		{
			return com_port_list;
		}
		public string GetDefaultPort()
		{
			string defPort;
			if(0 != com_port_list.Count){
				defPort = com_port_list[com_port_list.Count - 1];
			}
			else{
				defPort = "null";
			}
			return defPort;
		}
		
		public List<string> GetParityList()
		{
			return parity_list;
		}
		public string GetDefaultParity()
		{
			return "None(无)";
		}
		public List<string> GetDataBitList()
		{
			return data_bit_list;
		}
		public string GetDefaultDataBit()
		{
			return "8";
		}
		public List<string> GetStopBitList()
		{
			return stop_bit_list;
		}
		public string GetDefaultStopBit()
		{
			return "1";
		}
		public void SetCurrentCOMPort(string com)
		{
			sp.PortName = com;
		}
		public void SetCurrentBaudRate(string baudrate)
		{
			sp.BaudRate = Convert.ToInt32(baudrate);
		}
		public void SetCurrentParityBit(string pb)
		{
			sp.Parity= parity_dic[pb];
		}
		public void SetCurrentDataBit(string data_bit)
		{
			sp.DataBits = Convert.ToInt32(data_bit);
		}
		public void SetCurrentStopBit(string sb)
		{
			sp.StopBits = stop_bit_dic[sb];
		}
		
		public bool IsCOMPortOpen()
		{
			return sp_open_flag;
		}
		private void ShowSpInformation()
		{
			Console.WriteLine("port:{0}  bd:{1} pb:{2}",sp.PortName,sp.BaudRate,sp.Parity);
			Console.WriteLine("databit:{0} stopbit:{1}",sp.DataBits,sp.StopBits);
		}
		private void SetDefaultParameter()
		{
			sp.ReadTimeout = -1;
			sp.RtsEnable = true;
		}

		private void sp_DataReceived(object sender,SerialDataReceivedEventArgs e)
		{
			if (sp.BytesToRead > 1)
			{
				Thread.Sleep(20);
				Byte[] ReceivedData = new Byte[sp.BytesToRead];
				sp.Read(ReceivedData, 0, ReceivedData.Length);

				read_buf_mutex.WaitOne();
				try
				{
					for (int i = 0; i < ReceivedData.Length; i++)
					{
						read_buf.Add(ReceivedData[i]);
					}
				}
				finally
				{
					read_buf_mutex.ReleaseMutex();
				}
				sp.DiscardInBuffer();
			}
			else
			{
				Thread.Sleep(10);
			}
		}
		
		public void OpenCOMPort()
		{
			ShowSpInformation();
			SetDefaultParameter();

			sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
			sp.Open();

			sp_open_flag = true;
		}
		public void CloseCOMPort()
		{
			sp.Close();
			sp_open_flag = false;
		}
		
		public bool Read(out List<byte> dest)
		{
			bool ret = false;
			dest = new List<byte>();
			read_buf_mutex.WaitOne(100);
			try {
				if (read_buf.Count != 0) {
					dest.Clear();
					for (int i = 0; i < read_buf.Count; i++) {
						dest.Add(read_buf[i]);
					}
					read_buf.Clear();
				}
			}
			finally{
				read_buf_mutex.ReleaseMutex();
			}

			if (dest.Count > 0)
			{
				ret = true;
			}

			return ret;
		}
		
		public int Write(byte[] src)
		{
			if (src.Length == 0) {
				return -1;
			}
			if (true == sp_open_flag)
            {
                try
                {
                	sp.WriteTimeout = -1;
                	sp.Write(src,0,src.Length);
                }
                catch (Exception)
                {
                    return -1;
                }
                return src.Length;
            }else{
				return -1;
			}
		}
	}
}
